import { changeArrField } from "./index";
import { MessageBox, Message } from "element-ui";
import { getTableHeight } from "./table";
// --------------------表单------seart------------------------------------

/**
  * @param {Object} form 需要改变的表单
  * @param {that} this
  * @param {Object} api 表单中下拉宽需要获取的数据
  * @description 打开表单组件(新增)
  */
export const add = async(form, that, api) => {
  setFormVal(form, that, api);
};

/**
  * @param {Object} form 需要改变的表单
  * @param {that} this
  * @param {Object} api 表单中下拉宽需要获取的数据
  * @param {Object} row 需要回填内容
  * @description 打开表单组件(编辑)
  */
export const edit = async(form, that, api, row) => {
  setFormVal(form, that, api, row);
};

/**
  * @param {Object} row 参数集合
  * @param {Function} api 调用的接口
  * @param {string} hintMsg 提示消息
  * @param {Function} db 回调方法
  * @param {Object | string} data 接口的参数 或者 内容
  * @description 用于表格内的 启用/禁用/删除等操作
  */
export const changeStatus = (row, api, hintMsg, db, data, succeedMsg) => {
  MessageBox.confirm(hintMsg, "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning"
  }).then(() => {
    let _data = {};

    // 没有data 使用默认参数 是 string | number 默认设置为状态值
    if (!data || typeof data === "string" || typeof data === "number") {
      _data = {
        id: row.id,
        status: data
      };
    } else if (typeof data === "object") {
      Object.keys(data).forEach(key => {
        if (!data[key]) {
          // 从参数集合中获取 参数
          _data[key] = row[_data[key]];
        } else {
          // 使用传入的默认参数
          _data[key] = data[key];
        }
      });
    }

    api(_data).then(() => {
      Message.success(succeedMsg || "操作成功");

      // 回调
      db && db();
    });
  });
};

/**
  * @param {Function} db 查询方法
  * @param {boolean} flag 是否需要直接执行查询方法
  * @param {form} form 需要改变的表单字段
  * @param {Object} that this
  * @description 表单组件初始化
  */
export const initSearch = (db, flag, form, that) => {
  if (!db) {
    throw new Error("必须有查询函数");
  }

  that[form].refresh = db;
  if (flag) {
    db();
  }
};

/**
  * @param {number} number 需要展开的数量
  * @param {object} originObj 需要修改的对象
  * @param {flag} 展开收缩的标识
  * @param {that} this
  * @param {number} index 展开按钮的位置
  * @description 是否展开收缩表单查询表单
  */
export const shrinkage = (number, index, originObj, flag, that, table, defaultHeight, otherHeight) => {
  // 设置展开图标
  if (that[flag]) {
    that[originObj].btnList.btnList[index].icon = "ico_unfold";
    that[originObj].btnList.btnList[index].label = "展开";
  } else {
    that[originObj].btnList.btnList[index].icon = "menu-unfold";
    that[originObj].btnList.btnList[index].label = "收缩";
  }

  // 设置显示内容
  that[originObj].options.forEach((item, index) => {
    if (index >= number) {
      item.hide = that[flag];
    }
  });
  that[flag] = !that[flag];
  getTableHeight(originObj, table, that, defaultHeight, otherHeight);
};

/**
  * @param {string} form 需要改变的表单
  * @param {string} code 表单中需要修改的key
  * @param {that} this
  * @param {fontion} api 调用的接口
  * @param {string} query 查询的参数
  * @param {Array} displayField 返回参数显示和上传的参数字段
  * @description 下拉框远程搜索返回内容
  */
export const remoteMethod = async(form, code, that, api, query, displayField, key, flag) => {
  for (let i = 0; i < that[form].options.length; i++) {
    const { prop } = that[form].options[i];
    // 找到对应需要远程搜索的字段
    if (prop === code) {
      if (query || flag) {
        if (typeof that[form].options[i].attrs?.loading === "undefined") {
          throw new Error("请将loading属性加上避免接口获取等待时间太长");
        }
        try {
          // 打开加载loading
          that[form].options[i].attrs.loading = true;

          const _data = {
            name: query
          };

          // 防止有的key不是name
          if (key) {
            _data[key] = query;
          }
          // 获取下拉框内容
          const data = await api(_data) || [];
          const initDisplayField = displayField || ["value", "id"];

          // 有的查询接口可能是带分页
          const { records } = data || {};
          // 将内容装换为下拉框所需要的格式
          that[form].options[i].childern = changeArrField(records || data, initDisplayField[0], initDisplayField[1]);
          // 关闭加载loading
          that[form].options[i].attrs.loading = false;
        } catch (error) {
          console.log("执行错误 ");
          // 清空加载  清空下拉框内容
          that[form].options[i].attrs.loading = false;
          that[form].options[i].childern = [];
        }
      } else {
        that[form].options[i].childern = [];
      }
      return;
    }
  }
};

/**
  * @param {Object} form 需要改变的表单
  * @param {that} this
  * @param {Object} api 表单中下拉宽需要获取的数据
  * @param {Object} row 需要回填内容
  */
const setFormVal = async(form, that, api, row) => {
  // 打开编辑弹框表单
  that[form] = Object.assign(that[form], {
    formType: row ? "edit" : "add",
    visible: true
  });

  // 回填表格数据
  that[form].options.forEach(item => {
    const { retain } = item || {};

    // 不是编辑状态下  并且不需要保留的字段
    if (!row && !retain) {
      item.value = "";
    } else if (row) {
      // 编辑下直接回填数据
      item.value = row[item.prop] || "";
    }
  });

  if (api) {
    await setInitOptions(form, that, api);
  }
};

/**
  * @param {Object} form 需要改变的表单
  * @param {that} this
  * @param {Array} displayKeys 需要显示的表单项
  * @param {Object} hideKeys 需要隐藏的表单项
  */
export const isDisplay = (form, that, displayKeys = [], hideKeys = []) => {
  for (let i = 0; i < displayKeys.length; i++) {
    that[form].options[displayKeys[i]].hide = false;
  }
  for (let i = 0; i < hideKeys.length; i++) {
    that[form].options[hideKeys[i]].hide = true;
  }
};

/**
  * @param {Object} form 需要改变的表单
  * @param {that} this
  * @param {Object} fun 表单中下拉宽需要获取的数据
  * @param {Boolean} son 当前调用的是否是子组件
  * @param {String} value 调用子组件需要传递的参数值
  * @description 设置初始化下拉框中所需要的值
  */
export const setInitOptions = async(form, that, fun, son, value) => {
  // 需要设置下拉框数据字段集合
  const arr = Object.keys(fun);
  // 需要调用接口api集合
  const tasks = [];
  // 需要回填的字段集合
  const obj = {};

  // 默认获取的参数
  const initDisplayField = ["value", "id"];
  // 获取api调用
  for (let i = 0; i < arr.length; i++) {
    const { api, data, options, displayField, params, backfill } = fun[arr[i]] || {};
    if (!options.length) {
      if (!son) {
        // 第一层直接使用参数
        tasks.push(api(data || params));
      } else {
        // 后面的使用父组件参数
        const obj = data || params;
        obj[Object.keys(obj)] = value;
        tasks.push(api(obj));
      }

      obj[arr[i]] = {
        displayField: displayField || initDisplayField,
        options: options || [],
        backfill
      };
    }
  }

  // 统一调用api获取对应数据
  if (tasks.length) {
    const res = await Promise.all(tasks);
    // 回填下拉框内容 backfill
    Object.keys(obj).forEach((key, index) => {
      const { displayField, backfill } = obj[key] || {};
      // 有数据后不再使用接口数据  避免多级联动后再次打开弹框下拉框的值会被覆盖回来
      if (!fun[key]?.options?.length) {
        const options = changeArrField(res[index], displayField[0], displayField[1]);
        fun[key].options = options;

        // 回填下拉框第一位
        if (backfill) {
          fun[key].value = options[0]?.value;
        }
      }
    });
  }

  // 将下拉框内容设置到对应的字段中
  for (let i = 0; i < that[form].options.length; i++) {
    const { prop } = that[form].options[i] || {};
    if (fun[prop] && !that[form].options[i]?.childern?.length) {
      const { options, value, backfill, childern } = fun[prop] || {};
      that[form].options[i].childern = options;

      // 回填下拉框第一位
      if (backfill) {
        that[form].form[prop] = value;
        // 只有需要回填第一层下拉框，才需要获取向下的数据
        if (childern) {
          for (let i = 0; i < childern.length; i++) {
            // 递归获取对应下拉选择框内容
            await setInitOptions(form, that, childern[i], true, value);
          }
        }
      }
    }
  }
};

/**
  * @param {Object} form 需要改变的表单
  * @param {that} this
  * @param {String} code 表单中需要改变的字段 (多个以逗号隔开)
  * @param {Function | Array} 当前调用 api
  * @param {Boolean} backfill 是否需要回填
  * @param {displayField} backfill 返回参数显示和上传的参数字段
  * @description 设置子下拉框中所需要的值
  */
export const setSonOptions = async(form, that, code, api, data, backfill, displayField) => {
  const { options } = that[form];
  const initDisplayField = displayField || ["value", "id"];
  for (let i = 0; i < options.length; i++) {
    const { prop } = options[i];

    if (prop === code) {
      const options = await changeArrField(await api(data), initDisplayField[0], initDisplayField[1]);
      that[form].options[i].childern = options;
      // 回填子元素内容
      that[form].form[prop] = backfill ? options[0]?.value : "";
    }
  }
};

